#!/bin/bash
# WAL-G 安装脚本
# 版本: 1.0.4 (MinIO S3支持与自动初始化)

# 记录当前工作目录
CURRENT_DIR=$(pwd)

# 获取脚本所在目录的绝对路径
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)

# 根据脚本目录计算项目根目录路径
if [[ "$SCRIPT_DIR" == */scripts/install ]]; then
  # 如果脚本位于scripts/install目录中
  PROJECT_ROOT=$(cd "$SCRIPT_DIR/../.." && pwd)
elif [[ "$SCRIPT_DIR" == */scripts/* ]]; then
  # 如果脚本位于scripts目录或其他子目录中
  PROJECT_ROOT=$(echo "$SCRIPT_DIR" | sed 's|\(.*\)/scripts.*|\1|')
else
  # 否则假设当前目录是项目根目录
  PROJECT_ROOT=$(pwd)
fi

# 配置文件路径
CONFIG_FILE="$PROJECT_ROOT/config/backup_env.conf"

# 检查配置文件是否存在
if [ ! -f "$CONFIG_FILE" ]; then
  echo "错误: 配置文件不存在: $CONFIG_FILE"
  exit 1
fi

# 导入共用函数 - 使用绝对路径
COMMON_SCRIPT="$PROJECT_ROOT/scripts/common.sh"
if [ -f "$COMMON_SCRIPT" ]; then
  source "$COMMON_SCRIPT"
else
  echo "错误: 共用脚本不存在: $COMMON_SCRIPT"
  exit 1
fi

log_info "开始安装 WAL-G 3.0.7 (本地安装)..."
check_directory "$LOG_DIR"

WALG_VERSION="3.0.7"
ARCH=$(uname -m)
OS=$(uname -s | tr '[:upper:]' '[:lower:]')

# 将aarch64映射到arm64，x86_64映射到amd64
if [ "$ARCH" = "aarch64" ]; then
    ARCH="arm64"
elif [ "$ARCH" = "x86_64" ]; then
    ARCH="amd64"
fi

# 本地WAL-G目录
LOCAL_WALG_DIR="$PROJECT_ROOT/wal-g_3.0.7"
LOCAL_WALG_BIN="$LOCAL_WALG_DIR/wal-g-pg-${OS}-${ARCH}"
WALG_BIN_PATH="/usr/local/bin/wal-g"

log_info "检测系统: $OS $ARCH"
log_info "当前工作目录: $CURRENT_DIR"
log_info "脚本目录: $SCRIPT_DIR"
log_info "项目根目录: $PROJECT_ROOT"
log_info "WAL-G目录: $LOCAL_WALG_DIR"
log_info "使用本地WAL-G安装文件: $LOCAL_WALG_BIN"

# 验证WAL-G目录是否存在
if [ ! -d "$LOCAL_WALG_DIR" ]; then
    log_warn "指定的WAL-G目录不存在: $LOCAL_WALG_DIR"

    # 尝试在其他位置查找wal-g_3.0.7目录
    log_info "尝试在其他位置查找wal-g_3.0.7目录..."

    # 可能的位置1: 当前目录
    if [ -d "$CURRENT_DIR/wal-g_3.0.7" ]; then
        LOCAL_WALG_DIR="$CURRENT_DIR/wal-g_3.0.7"
        log_info "在当前目录找到WAL-G目录: $LOCAL_WALG_DIR"
    # 可能的位置2: 脚本目录
    elif [ -d "$SCRIPT_DIR/wal-g_3.0.7" ]; then
        LOCAL_WALG_DIR="$SCRIPT_DIR/wal-g_3.0.7"
        log_info "在脚本目录找到WAL-G目录: $LOCAL_WALG_DIR"
    # 可能的位置3: 递归查找
    else
        FOUND_DIR=$(find "$CURRENT_DIR" -type d -name "wal-g_3.0.7" -print -quit 2>/dev/null)
        if [ -n "$FOUND_DIR" ]; then
            LOCAL_WALG_DIR="$FOUND_DIR"
            log_info "通过搜索找到WAL-G目录: $LOCAL_WALG_DIR"
        else
            handle_error 1 "无法找到wal-g_3.0.7目录，请确保该目录存在"
        fi
    fi

    # 更新二进制文件路径
    LOCAL_WALG_BIN="$LOCAL_WALG_DIR/wal-g-pg-${OS}-${ARCH}"
fi

# 检查本地文件是否存在
if [ ! -f "$LOCAL_WALG_BIN" ]; then
    log_warn "本地WAL-G文件不存在: $LOCAL_WALG_BIN"

    # 检查其他可能的文件名
    available_files=$(find "$LOCAL_WALG_DIR" -name "wal-g-pg-*" -type f)
    if [ -n "$available_files" ]; then
        log_info "发现可用的WAL-G文件:"
        echo "$available_files"

        # 使用第一个找到的文件
        LOCAL_WALG_BIN=$(echo "$available_files" | head -n 1)
        log_info "将使用: $LOCAL_WALG_BIN"
    else
        handle_error 1 "找不到任何可用的WAL-G文件，请确保wal-g_3.0.7目录包含WAL-G二进制文件"
    fi
fi

# 设置权限并移动到目标目录
log_info "复制WAL-G到 $WALG_BIN_PATH..."
cp "$LOCAL_WALG_BIN" "$WALG_BIN_PATH" || handle_error 2 "复制WAL-G到 $WALG_BIN_PATH 失败"
chmod +x "$WALG_BIN_PATH" || handle_error 2 "设置WAL-G可执行权限失败"

log_info "WAL-G已安装到 $WALG_BIN_PATH"

# 安装依赖 - 可选步骤
log_info "准备安装WAL-G辅助工具和依赖..."
log_info "注意: 预编译的WAL-G二进制文件可能已包含核心功能，但某些特性可能仍需这些依赖"
log_info "安装的依赖包括:"
log_info "  - postgresql-client: 用于与PostgreSQL数据库交互"
log_info "  - lzop, pigz: 用于WAL-G的压缩功能"
log_info "  - pv: 用于监控数据传输进度"
log_info "  - s3cmd: 用于MinIO存储桶初始化"

read -p "是否继续安装这些依赖? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    log_info "安装WAL-G依赖中..."
    apt-get update
    apt-get install -y postgresql-client lzop pv pigz s3cmd curl jq
    log_info "依赖安装完成"
else
    log_info "跳过依赖安装"
    log_info "如果WAL-G运行时出现问题，您可能需要手动安装所需的依赖"
fi

# 创建WAL-G配置目录
WALG_CONFIG_DIR="/etc/wal-g"
check_directory "$WALG_CONFIG_DIR"

# 创建WAL-G环境配置文件 - 本地文件系统
cat > "$WALG_CONFIG_DIR/environment_local" <<EOF
# WAL-G环境配置 - 本地文件系统

# 存储类型: 本地文件系统
WALG_FILE_PREFIX="file://localhost$BACKUP_BASE_DIR"

# PostgreSQL连接
PGHOST=localhost
PGPORT=5432
PGUSER=$POSTGRES_SUPERUSER
PGPASSWORD=$POSTGRES_PASSWORD
PGDATABASE=$THINGSBOARD_DATABASE_NAME

# 压缩设置
WALG_COMPRESSION_METHOD=lz4
EOF

log_info "WAL-G本地文件系统配置已创建: $WALG_CONFIG_DIR/environment_local"

# 创建WAL-G环境配置文件 - MinIO S3存储
cat > "$WALG_CONFIG_DIR/environment" <<EOF
# WAL-G环境配置 - MinIO S3存储

# 存储类型: MinIO S3
WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_FULL_PREFIX}"
AWS_ACCESS_KEY_ID="${MINIO_USER}"
AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}"
AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}"
AWS_S3_FORCE_PATH_STYLE="true"

# PostgreSQL连接
PGHOST=localhost
PGPORT=5432
PGUSER=$POSTGRES_SUPERUSER
PGPASSWORD=$POSTGRES_PASSWORD
PGDATABASE=$THINGSBOARD_DATABASE_NAME

# 压缩设置
WALG_COMPRESSION_METHOD=lz4
EOF

log_info "WAL-G MinIO S3配置已创建: $WALG_CONFIG_DIR/environment"

# 创建Docker的WAL-G环境配置文件 - MinIO S3存储
if [ "$USE_DOCKER" = "true" ]; then
    cat > "$WALG_CONFIG_DIR/docker_environment" <<EOF
# Docker环境下的WAL-G配置 - MinIO S3存储

# 存储类型: MinIO S3
WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_FULL_PREFIX}"
AWS_ACCESS_KEY_ID="${MINIO_USER}"
AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}"
AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}"
AWS_S3_FORCE_PATH_STYLE="true"

# PostgreSQL连接
PGHOST=localhost
PGPORT=5432
PGUSER=$POSTGRES_SUPERUSER
PGPASSWORD=$POSTGRES_PASSWORD
PGDATABASE=$THINGSBOARD_DATABASE_NAME

# 压缩设置
WALG_COMPRESSION_METHOD=lz4
EOF

    log_info "Docker环境MinIO WAL-G配置已创建: $WALG_CONFIG_DIR/docker_environment"
fi

# 验证安装
log_info "验证WAL-G安装..."
if ! wal-g --version; then
    handle_error 3 "WAL-G安装验证失败"
fi

# 创建WAL-G所需的目录结构
log_info "创建WAL-G所需的目录结构..."
mkdir -p "$BACKUP_BASE_DIR/basebackups_005"
touch "$BACKUP_BASE_DIR/basebackups_005/.sentinel"
chmod -R 755 "$BACKUP_BASE_DIR"

# 配置PostgreSQL归档日志
if [ "$WAL_ARCHIVE_ENABLED" = "true" ]; then
    log_info "配置PostgreSQL WAL归档..."

    # 创建归档目录
    check_directory "$WAL_ARCHIVE_DIR"

    # 为Docker容器中的PostgreSQL配置WAL归档
    if [ "$USE_DOCKER" = "true" ]; then
        # 创建归档脚本
        cat > "$WALG_CONFIG_DIR/archive_wal.sh" <<EOF
#!/bin/bash
source $WALG_CONFIG_DIR/environment
wal-g wal-push \$1
EOF
        chmod +x "$WALG_CONFIG_DIR/archive_wal.sh"

        # 修改PostgreSQL配置
        log_info "配置Docker PostgreSQL容器的归档设置..."
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "echo \"wal_level = replica\" >> /var/lib/postgresql/data/postgresql.conf"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "echo \"archive_mode = on\" >> /var/lib/postgresql/data/postgresql.conf"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "echo \"archive_command = '$WALG_CONFIG_DIR/archive_wal.sh %p'\" >> /var/lib/postgresql/data/postgresql.conf"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "echo \"archive_timeout = 60\" >> /var/lib/postgresql/data/postgresql.conf"

        log_info "重启PostgreSQL容器以应用WAL归档设置..."
        docker restart "$POSTGRES_CONTAINER_NAME"
    else
        # 本地PostgreSQL的WAL归档配置
        log_warn "本地PostgreSQL WAL归档配置未实现，请手动配置"
    fi
fi

# 初始化MinIO存储桶
if [ -n "$MINIO_HOST" ] && [ -n "$MINIO_PORT" ] && [ -n "$MINIO_USER" ] && [ -n "$MINIO_PASSWORD" ] && [ -n "$MINIO_BUCKET" ]; then
    log_info "尝试初始化MinIO存储..."

    # 检查MinIO服务是否可访问
    if curl -s --connect-timeout 5 "http://$MINIO_HOST:$MINIO_PORT/minio/health/live" > /dev/null; then
        log_info "MinIO服务器连接成功"

        # 创建s3cmd配置文件
        TEMP_S3CFG=$(mktemp)
        cat > "$TEMP_S3CFG" << EOF
[default]
access_key = $MINIO_USER
secret_key = $MINIO_PASSWORD
host_base = $MINIO_HOST:$MINIO_PORT
host_bucket = $MINIO_HOST:$MINIO_PORT
use_https = False
signature_v2 = False
EOF

        # 检查存储桶是否存在，不存在则创建
        if ! s3cmd -c "$TEMP_S3CFG" ls "s3://$MINIO_BUCKET" > /dev/null 2>&1; then
            log_info "创建MinIO存储桶: $MINIO_BUCKET"
            s3cmd -c "$TEMP_S3CFG" mb "s3://$MINIO_BUCKET" || log_warn "创建存储桶失败，可能需要手动创建"
        else
            log_info "存储桶已存在: $MINIO_BUCKET"
        fi

        # 创建所需的目录结构
        log_info "在MinIO中创建目录结构..."
        S3_DIRS=("$MINIO_FULL_PREFIX" "$MINIO_DIFF_PREFIX" "$MINIO_FULL_PREFIX/basebackups_005" "$MINIO_FULL_PREFIX/wal_005")

        for dir in "${S3_DIRS[@]}"; do
            # MinIO中的目录是通过上传空文件来创建的
            echo "" > /tmp/empty_file
            s3cmd -c "$TEMP_S3CFG" put /tmp/empty_file "s3://$MINIO_BUCKET/$dir/.keep" > /dev/null 2>&1 || log_warn "创建目录失败: $dir"
            log_info "创建目录: $MINIO_BUCKET/$dir"
        done

        # 清理临时文件
        rm -f "$TEMP_S3CFG" /tmp/empty_file

        log_success "MinIO存储初始化完成"
    else
        log_warn "无法连接到MinIO服务器，请确保MinIO服务已启动并且配置正确"
        log_warn "您可能需要手动创建存储桶和目录结构"
    fi
else
    log_warn "MinIO配置不完整，无法初始化MinIO存储"
fi

# 创建WAL-G配置文件（YAML或JSON格式）
cat > "$HOME/.walg.json" <<EOF
{
  "WALG_S3_PREFIX": "s3://${MINIO_BUCKET}/${MINIO_FULL_PREFIX}",
  "AWS_ACCESS_KEY_ID": "${MINIO_USER}",
  "AWS_SECRET_ACCESS_KEY": "${MINIO_PASSWORD}",
  "AWS_ENDPOINT": "http://${MINIO_HOST}:${MINIO_PORT}",
  "AWS_S3_FORCE_PATH_STYLE": "true",
  "PGHOST": "localhost",
  "PGPORT": "5432",
  "PGUSER": "$POSTGRES_SUPERUSER",
  "PGPASSWORD": "$POSTGRES_PASSWORD",
  "PGDATABASE": "$THINGSBOARD_DATABASE_NAME",
  "WALG_COMPRESSION_METHOD": "lz4"
}
EOF

# 回到原始目录
cd "$CURRENT_DIR" || true

log_info "WAL-G $WALG_VERSION 安装和配置完成"
log_info "使用方法示例:"
log_info "1. 使用MinIO S3存储 (默认):"
log_info "   wal-g backup-list"
log_info "2. 使用本地文件系统存储:"
log_info "   WALG_FILE_PREFIX=\"file://localhost$BACKUP_BASE_DIR\" wal-g backup-list"
